import { expect } from 'chai';
import * as sinon from 'sinon';
import * as path from 'path';

import * as step from '@flow-step/step-toolkit'
import {execute} from '../src/step'
import {TestParser} from '../src/test-parser'

describe('execute', () => {
    let mockParser: TestParser;
    let parseStub: sinon.SinonStub
    let coverageFileStub: sinon.SinonStub
    let htmlFileStub: sinon.SinonStub
    let outputResultStub: sinon.SinonStub;
    let debugStub: sinon.SinonStub;
    let getParserStub: sinon.SinonStub;

    beforeEach(() => {
        getParserStub = sinon.stub(require('../src/test-parser'), 'getParser');
        outputResultStub = sinon.stub(step.testCase, 'outputResult');
        debugStub = sinon.stub(step, 'debug');
        parseStub = sinon.stub()
        coverageFileStub = sinon.stub()
        htmlFileStub = sinon.stub()


        sinon.stub(process, 'env').value({
            REPORT_PATH: 'reports/report.html',
            PROJECT_DIR: '/project',
            REPORTER: 'Java-JUnit',
            FAIL_ON_ERROR: 'true'
        });
        mockParser = {
            coverageFile: coverageFileStub,
            parse: parseStub,
            htmlFile: htmlFileStub
        }
        getParserStub.returns(mockParser);
    });

    afterEach(() => {
        sinon.restore();
    });

    it('should parse the report and output the result', async () => {
        coverageFileStub.returns(path.join('/project', 'reports/report.html'))
        htmlFileStub.returns(path.join('/project', 'reports/report.html'))

        const coverage = { failed: 0, passed: 10 };
        parseStub.resolves(coverage);

        await execute();

        expect(parseStub.calledWith(path.join('/project', 'reports/report.html'))).to.be.true;
        expect(debugStub.calledWith(`coverage: ${JSON.stringify(coverage)}`)).to.be.true;
        expect(outputResultStub.calledWith({
            reportLocalPath: path.join('/project', 'reports/report.html'),
            coverage: coverage
        })).to.be.true;
    });

    it('should throw an error if there are failed test cases and FAIL_ON_ERROR is true', async () => {
        coverageFileStub.returns(path.join('/project', 'reports/report.html'))
        htmlFileStub.returns(path.join('/project', 'reports/report.html'))
        const coverage = { failed: 1, passed: 9 };
        parseStub.resolves(coverage);

        try {
            await execute();
            expect.fail('Expected an error to be thrown');
        } catch (error: any) {
            expect(error.message).to.equal('step failed because of failed test case(s)');
        }
    });

    it('should not throw an error if there are failed test cases but FAIL_ON_ERROR is false', async () => {
        coverageFileStub.returns(path.join('/project', 'reports/report.html'))
        htmlFileStub.returns(path.join('/project', 'reports/report.html'))
        const coverage = { failed: 1, passed: 9 };
        parseStub.resolves(coverage);

        process.env.FAIL_ON_ERROR = 'false';

        await execute();

        expect(outputResultStub.calledWith({
            reportLocalPath: path.join('/project', 'reports/report.html'),
            coverage: coverage
        })).to.be.true;
    });
});
